<i18n locale="zh-CN" lang="yaml">
Schema Browser: 结构浏览器

Guance DataWay: 观测云DataWay

Run InfluxQL     : 执行 InfluxQL
Run SQL          : 执行 SQL
Run Command      : 执行命令
Send HTTP Request: 发送 HTTP 请求

Database          : 数据库
Table             : 表
Field             : 字段
Data              : 数据
Measurement       : 指标
Tag               : 标签
Index             : 索引
Collection        : 集合
Retention Policie : 保留策略
Initial           : 首字母
'Keys (a part of)': 键（部分）
Other             : 其他

Cannot connect to this Connector, check the configs and try again.: 无法使用此连接器，请检查配置后重试。
Error Message: 错误信息如下
Query is running. It waits up to 5 seconds, You can refresh the page when it not response for a long time.: 查询执行中，最多等待 5 秒，长时间无响应后再尝试刷新页面
'Results will be shown here...': '执行结果将显示在此...'
Query Failed: 查询失败

Run        : 执行
Query      : 查询语句
Python Code: Python 代码
Result     : 结果
</i18n>

<!-- Generated by OpenCC START -->
<i18n locale="zh-HK" lang="yaml">
Cannot connect to this Connector, check the configs and try again.: 無法使用此連接器，請檢查配置後重試。
Collection: 集合
Data: 數據
Database: 數據庫
Error Message: 錯誤信息如下
Field: 字段
Guance DataWay: 觀測雲DataWay
Index: 索引
Initial: 首字母
Keys (a part of): 鍵（部分）
Measurement: 指標
Other: 其他
Python Code: Python 代碼
Query: 查詢語句
Query Failed: 查詢失敗
Query is running. It waits up to 5 seconds, You can refresh the page when it not response for a long time.: 查詢執行中，最多等待 5 秒，長時間無響應後再嘗試刷新頁面
Result: 結果
Results will be shown here...: 執行結果將顯示在此...
Retention Policie: 保留策略
Run: 執行
Run Command: 執行命令
Run InfluxQL: 執行 InfluxQL
Run SQL: 執行 SQL
Schema Browser: 結構瀏覽器
Send HTTP Request: 發送 HTTP 請求
Table: 表
Tag: 標籤
</i18n>
<i18n locale="zh-TW" lang="yaml">
Cannot connect to this Connector, check the configs and try again.: 無法使用此聯結器，請檢查配置後重試。
Collection: 集合
Data: 資料
Database: 資料庫
Error Message: 錯誤資訊如下
Field: 欄位
Guance DataWay: 觀測雲DataWay
Index: 索引
Initial: 首字母
Keys (a part of): 鍵（部分）
Measurement: 指標
Other: 其他
Python Code: Python 程式碼
Query: 查詢語句
Query Failed: 查詢失敗
Query is running. It waits up to 5 seconds, You can refresh the page when it not response for a long time.: 查詢執行中，最多等待 5 秒，長時間無響應後再嘗試重新整理頁面
Result: 結果
Results will be shown here...: 執行結果將顯示在此...
Retention Policie: 保留策略
Run: 執行
Run Command: 執行命令
Run InfluxQL: 執行 InfluxQL
Run SQL: 執行 SQL
Schema Browser: 結構瀏覽器
Send HTTP Request: 傳送 HTTP 請求
Table: 表
Tag: 標籤
</i18n>
<!-- Generated by OpenCC END -->

<template>
  <div id="connectorSimpleGUIWindow"
    class="connector-simple-gui-window"
    v-if="show && connector"
    :style="{top: showPosition.top + 'px', left: showPosition.left + 'px'}">
    <div @mousedown="startDrag" class="connector-simple-gui-header">
      <span class="connector-simple-gui-title">
        <el-tag :type="C.CONNECTOR_MAP.get(connector.type).tagType" size="mini"><span>{{ C.CONNECTOR_MAP.get(connector.type).name }}</span></el-tag>
        <span :class="{ builtin: connector.isBuiltin }">{{ connector.title || connector.id }}</span>
      </span>
      <el-link :underline="false" class="connector-simple-gui-close" @mousedown.native.stop @click.stop="hideWindow()"><i class="fa fa-times"></i> {{ $t('Close') }}</el-link>
    </div>

    <el-tabs
      tab-position="bottom"
      type="border-card"
      v-model="selectedTab">
      <el-tab-pane
        v-if="META_MAP[connector.type].supportBrowser"
        :label="$t('Schema Browser')"
        name="browser">
        <div class="connector-simple-gui-browser">
          <el-link type="danger" v-if="browserCascaderErrorMessage">
            {{ $t('Cannot connect to this Connector, check the configs and try again.') }}
            <br>{{ $t('Error Message') }}{{ $t(':') }}
            <pre class="connector-simple-gui-browser-error">{{ browserCascaderErrorMessage }}</pre>
          </el-link>
          <el-form v-else>
            <el-form-item>
              <el-cascader-panel class="connector-simple-gui-browser-cascader" :class="!!browserCascaderExampleCode ? 'normal-window' : 'full-window'" ref="browserCascader"
                placeholder="--"
                size="mini"
                :props="browserCascaderProps">
                <div slot-scope="{ node, data }" @click="updateCodeExample(node)" class="connector-simple-gui-browser-cascader-item">
                  <el-tag v-if="data.showDefaultTag"
                    plain
                    size="mini">{{ $t('Default') }}</el-tag>
                  <el-tag v-if="data.dbTag"
                    plain
                    :type="data.dbTag.type"
                    size="mini">{{ data.dbTag.title }}</el-tag>
                  <span :class="{'text-bad': data.isError}">{{ data.label || data.value }}</span>
                  <span v-if="data.itemCount"> ({{ data.itemCount }}) </span>
                </div>
              </el-cascader-panel>
            </el-form-item>
            <el-form-item v-if="!!browserCascaderExampleCode">
              <pre class="connector-simple-gui-browser-example-code"
                rows="2">{{ browserCascaderExampleCode }}</pre>
              <div class="connector-simple-gui-browser-example-code-edit">
                <i class="fa fa-fw fa-terminal text-main"></i>
              </div>
              <el-button type="text"
                class="connector-simple-gui-browser-example-code-run"
                @click="copyCascaderExampleCodeToDebugger"
                v-show="browserCascaderExampleCode">
                <i class="fa fa-fw fa-share text-main"></i>
                {{ $t('Run') }}
              </el-button>
            </el-form-item>
          </el-form>
        </div>
      </el-tab-pane>
      <el-tab-pane
        v-if="META_MAP[connector.type].supportDebugger"
        :label="META_MAP[connector.type].debuggerName"
        name="debugger">
        <div class="connector-simple-gui-debugger"
          v-loading.lock="isQuerying"
          element-loading-spinner="el-icon-loading"
          :element-loading-text="$t('Query is running. It waits up to 5 seconds, You can refresh the page when it not response for a long time.')">
          <el-form>
            <el-form-item>
              <el-input
                type="textarea"
                resize="none"
                rows="3"
                v-model="latestQueryOptionsMap[connector.id].queryStatement"></el-input>
            </el-form-item>
            <el-form-item>
              <template v-if="META_MAP[connector.type].supportDatabase">
                &nbsp;
                <span>{{ $t('Database') }}</span>
                <el-input class="connector-simple-gui-database" size="mini" v-if="!connector.configJSON.database" v-model="latestQueryOptionsMap[connector.id].database"></el-input>
                <el-input class="connector-simple-gui-database" size="mini" v-else :disabled="true" :value="connector.configJSON.database"></el-input>
              </template>

              <el-button
                size="mini"
                @click.stop="runDebugger(latestQueryOptionsMap[connector.id])">
                <i class="fa fa-fw fa-play"></i> {{ $t('Run') }}
              </el-button>
              <div class="connector-simple-gui-copy-content" v-if="latestQueryResultMap[connector.id] && latestQueryResultMap[connector.id].ok">
                <CopyButton tipPlacement="bottom" :title="$t('Query')" :content="latestQueryOptionsMap[connector.id].queryStatement" />
                &nbsp;
                <CopyButton tipPlacement="bottom" :title="$t('Python Code')" :content="latestQueryOptionsMap[connector.id].pythonCode" />
                &nbsp;
                <CopyButton tipPlacement="bottom" :title="$t('Result')" :content="latestQueryResultMap[connector.id].data" />
              </div>
            </el-form-item>
            <el-form-item>
              <pre
                class="connector-simple-gui-result"
                :class="{'connector-simple-gui-query-failed': latestQueryResultMap[connector.id] && !latestQueryResultMap[connector.id].ok}"
                rows="5">{{ latestQueryResultMap[connector.id] && latestQueryResultMap[connector.id].data || $t('Results will be shown here...')}}</pre>
            </el-form-item>
          </el-form>
        </div>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
import splitargs from 'splitargs';

export default {
  name: 'ConnectorSimpleGUIWindow',
  components: {
  },
  watch: {
    connector(val) {
      if (this.$refs.browserCascader) {
        this.$refs.browserCascader.clearCheckedNodes();
        this.$refs.browserCascader.initStore();
        this.browserCascaderExampleCode = '';
      }
    },
  },
  methods: {
    async showWindow(connector) {
      this.browserCascaderErrorMessage = '';

      let meta = this.META_MAP[connector.type];
      if (meta.supportDebugger) {
        let command     = meta.command;
        let commandArgs = meta.debuggerExample;

        if (!this.latestQueryOptionsMap[connector.id]) {
          let getHelperCode = `helper = DFF.CONN('${connector.id}')`;
          let doQueryCode   = `helper.${command}('${commandArgs.join("', '")}')`;

          this.$set(this.latestQueryOptionsMap, connector.id, {
            database      : connector.database,
            queryStatement: commandArgs.join(' '),
            pythonCode    : `${getHelperCode}\n${doQueryCode}`,
          });
        }
      }

      this.connector = connector;
      this.show = true;

      // Switch to first Tab automatically
      if (meta.supportBrowser) {
        this.selectedTab = 'browser';
      } else if (meta.supportDebugger) {
        this.selectedTab = 'debugger';
      }

      setImmediate(() => {
        this.fixShowPosition();
      });
    },
    hideWindow() {
      this.show = false;
    },
    startDrag(event) {
      let $this = document.getElementById('connectorSimpleGUIWindow');

      let offsetX = event.screenX - $this.offsetLeft;
      let offsetY = event.screenY - $this.offsetTop;

      document.onmousemove = docEvent => {
        let nextLeft = (docEvent || event).screenX - offsetX;
        let nextTop  = (docEvent || event).screenY - offsetY;

        let maxLeft = window.innerWidth  - $this.offsetWidth - 10;
        let maxTop  = window.innerHeight - $this.offsetHeight - 10;

        // Position limiter
        if (nextLeft < 0) nextLeft = 0;
        if (nextTop  < 0) nextTop = 0;
        if (nextLeft > maxLeft) nextLeft = maxLeft;
        if (nextTop  > maxTop)  nextTop  = maxTop;

        let nextDragPosition = {
          left: nextLeft,
          top : nextTop,
        };

        this.dragPosition = nextDragPosition;
        this.$store.commit('updateAsideConnector_connectorSimpleGUIWindowPosition', this.dragPosition);

        this.fixShowPosition();
      };
      document.onmouseup = docEvent => {
        document.onmousemove = null;
        document.onmouseup   = null;
      };
    },
    fixShowPosition() {
      var nextShowPosition = {
        top : this.dragPosition.top,
        left: this.dragPosition.left,
      };

      let $this = document.getElementById('connectorSimpleGUIWindow');
      if (!$this) return;

      let maxLeft = window.innerWidth  - $this.offsetWidth - 10;
      let maxTop  = window.innerHeight - $this.offsetHeight - 10;

      // Position limiter
      if (nextShowPosition.left < 0) nextShowPosition.left = 0;
      if (nextShowPosition.top  < 0) nextShowPosition.top = 0;
      if (nextShowPosition.left > maxLeft) nextShowPosition.left = maxLeft;
      if (nextShowPosition.top  > maxTop)  nextShowPosition.top  = maxTop;

      this.showPosition = nextShowPosition;
    },
    async loadBrowser(node, resolve) {
      if (node.isLeaf) return resolve();

      let meta = this.META_MAP[this.connector.type];
      if (!meta.browser) return resolve();

      /* Parent data */
      let parentData = [];
      if (!node.root) {
        let currentNode = node;
        for (let i = 0; i < 10; i++) {
          if (!currentNode || currentNode.root || !currentNode.data) break;

          parentData.push(currentNode.data);
          currentNode = currentNode.parent;
        }
        parentData.reverse();
      }

      /* Navi to current node config */
      let browseOpt = meta.browser;

      for (let level = 0; level < node.level; level++) {
        switch(browseOpt.type) {
          case 'static':
            for (let i = 0; i < browseOpt.data.length; i++) {
              if (browseOpt.data[i].value === parentData[level].value) {
                browseOpt = browseOpt.data[i].sub;
                break;
              }
            }
            break;

          case 'query':
            browseOpt = browseOpt.sub;
            break;
        }
      }

      /* Get child data */
      const buildCommandArgs = (commandArgs) => {
        if (!commandArgs) return undefined;

        commandArgs = this.T.jsonCopy(commandArgs);

        parentData.forEach(d => {
          if (d.ref && d.value) {
            let argIndex = commandArgs.indexOf(`$${d.ref}`);
            if (argIndex >= 0) {
              commandArgs[argIndex] = d.value;
            }
          }
        });

        return commandArgs;
      }
      const buildCommandKwargs = (commandKwargs) => {
        if (!commandKwargs) return undefined;

        commandKwargs = this.T.jsonCopy(commandKwargs);

        parentData.forEach(d => {
          if (d.ref && d.value && (d.ref in commandKwargs)) {
            commandKwargs[d.ref] = d.value;
          }
        });

        return commandKwargs;
      }
      const formatQueryStatement = (statement, thisRef, thisValue) => {
        if (!statement) return undefined;

        parentData.forEach(d => {
          if (d.ref && d.value) {
            statement = statement.replace(`{${d.ref}}`, d.value);
          }
        });

        if (thisRef && thisValue) {
          statement = statement.replace(`{${thisRef}}`, thisValue);
        }
        return statement;
      }

      let apiRes = null;
      let subNodeData = [];
      switch(browseOpt.type) {
        // Static list
        case 'static':
          browseOpt.data.forEach(d => {
            subNodeData.push({
              label: d.label,
              value: d.value,
              ref  : d.ref,
              leaf : !!!d.sub,

              example       : formatQueryStatement(d.example,        d.ref, d.value),
              defaultExample: formatQueryStatement(d.defaultExample, d.ref, d.value),
            });
          });
          break;

        // Call query to get list
        case 'query':
          let body = {
            command       : browseOpt.command,
            commandArgs   : buildCommandArgs(browseOpt.commandArgs),
            commandKwargs : buildCommandKwargs(browseOpt.commandKwargs),
            queryStatement: formatQueryStatement(browseOpt.query),
            database      : this.connector.configJSON.database,
            returnType    : 'json',
          };

          // Query data
          apiRes = await this.T.callAPI('post', '/api/v1/connectors/:id/do/query', {
            params      : { id: this.connector.id },
            body        : body,
            feedback    : { muteError        : true },
            extraOptions: { noCountProcessing: true },
          });
          if (!apiRes.ok) {
            if (node.root) {
              this.browserCascaderErrorMessage = apiRes.message;
            } else {
              resolve([{
                label   : this.$t('Query Failed'),
                value   : null,
                leaf    : true,
                disabled: true,
                isError : true,
              }]);
            }

            return;
          }

          // Pick data
          switch(this.connector.type) {
            case 'influxdb':
              if (apiRes.data.series && apiRes.data.series.length > 0) {
                apiRes.data.series[0].values.forEach(d => {
                  subNodeData.push({ value: d[0] });
                });
              }
              break;

            case 'mysql':
              apiRes.data.forEach(d => {
                switch(browseOpt.ref) {
                  case 'table':
                    subNodeData.push({ value: Object.values(d)[0] });
                    break;

                  case 'field':
                    subNodeData.push({ value: d['Field'] });
                    break;
                }
              });
              break;

            case 'redis':
              apiRes.data[1].forEach(d => {
                subNodeData.push({ value: d });
              })
              break;

            case 'clickhouse':
              apiRes.data.forEach(d => {
                switch(browseOpt.ref) {
                  case 'database':
                  case 'table':
                    subNodeData.push({ value: d['name'] });
                    break;

                  case 'field':
                    subNodeData.push({ value: d['name'] });
                    break;
                }
              });
              break;

            case 'oracle':
              apiRes.data.forEach(d => {
                switch(browseOpt.ref) {
                  case 'table':
                    subNodeData.push({ value: d['TABLE_NAME'] });
                    break;

                  case 'field':
                    subNodeData.push({ value: d['COLUMN_NAME'] });
                    break;
                }
              });
              break;

            case 'sqlserver':
              apiRes.data.forEach(d => {
                switch(browseOpt.ref) {
                  case 'table':
                  case 'field':
                    subNodeData.push({ value: d['NAME'] });
                    break;
                }
              });
              break;

            case 'postgresql':
              apiRes.data.forEach(d => {
                switch(browseOpt.ref) {
                  case 'schema':
                    subNodeData.push({ value: d['schemaname'] });
                    break;

                  case 'table':
                    subNodeData.push({ value: d['tablename'] });
                    break;

                  case 'field':
                    subNodeData.push({ value: d['attname'] });
                    break;
                }
              });
              break;

            case 'mongodb':
              apiRes.data.forEach(d => {
                switch(browseOpt.ref) {
                  case 'database':
                  case 'collection':
                    subNodeData.push({ value: d });
                    break;
                }
              });
              break;

            case 'elasticsearch':
              switch(browseOpt.ref) {
                case 'index':
                  apiRes.data.forEach(d => {
                    subNodeData.push({ value: d['index'] });
                  })
                  break;

                case 'field':
                  let _fields = [];
                  try {
                    _fields = Object.keys(Object.values(apiRes.data)[0]['mappings']['properties'])
                  } catch(err) {
                    // Nope
                  };

                  _fields.forEach(d => {
                    subNodeData.push({ value: d });
                  });
                  break;

                default:
                  break;
              }
              break;

            case 'prometheus':
              switch(browseOpt.ref) {
                case 'metric':
                  apiRes.data.data.forEach(d => {
                    subNodeData.push({ value: d });
                  })
                  break;
              }
              break;

            case 'aliyunSLS':
              switch(browseOpt.ref) {
                case 'project':
                case 'logstore':
                  apiRes.data.forEach(d => {
                    subNodeData.push({ value: d });
                  })
                  break;
              }
              break;
          }
          break;
      }

      /* Ensure other fields */
      switch(browseOpt.type) {
        case 'query':
          subNodeData.forEach(d => {
            d.ref  = browseOpt.ref;
            d.leaf = !!!browseOpt.sub;

            d.example        = formatQueryStatement(browseOpt.example,        d.ref, d.value);
            d.defaultExample = formatQueryStatement(browseOpt.defaultExample, d.ref, d.value);
          });
          break;

        case 'static':
        default:
          break;
      }

      /* Ensure isDefaultDatabase field */
      subNodeData.forEach(d => {
        d.isDefaultDatabase = (d.ref === 'database' && d.value === this.connector.configJSON.database);
        if (!d.isDefaultDatabase) {
          parentData.forEach(p => {
            if (p.ref === 'database' && p.value ===  this.connector.configJSON.database) {
              d.isDefaultDatabase = true;
            }
          });
        }
        if (d.isDefaultDatabase && d.ref === 'database') {
          d.showDefaultTag = true;
        }
      });

      /* Use a disabled option as title */
      let itemCount = subNodeData.length;
      let title = browseOpt.title || '';
      if (title && itemCount > 0) title = `${title} (${itemCount})`;
      subNodeData.unshift({
        label   : title,
        value   : null,
        leaf    : true,
        disabled: true,
        isTitle : true,
      });
      if (!node.root) {
        this.$set(node.data, 'itemCount', itemCount);
      }

      return resolve(subNodeData);
    },
    updateCodeExample(node) {
      // Show Sample code
      this.browserCascaderExampleCode = node.data.isDefaultDatabase
                                      ? node.data.defaultExample || node.data.example
                                      : node.data.example;
    },
    async runDebugger(queryOptions) {
      this.isQuerying = true;

      let apiRes = await this.T.callAPI('post', '/api/v1/connectors/:id/do/query', {
        params: { id: this.connector.id },
        body: {
          database      : queryOptions.database,
          queryStatement: queryOptions.queryStatement,
          returnType    : 'repr',
        },
        feedback    : { muteError: true },
        extraOptions: { noCountProcessing: true },
      });

      let result = {
        ok: apiRes.ok
      };

      if (apiRes.ok) {
        result.data = '# print(pprint.pformat(db_res))\n' + apiRes.data;

        // Gen sample Python code
        let command     = this.META_MAP[this.connector.type].command;
        let commandArgs = null;

        let resStr    = '';
        let resPicker = '';
        switch(this.connector.type) {
          case 'influxdb':
            commandArgs = [queryOptions.queryStatement];
            resPicker = `if len(db_res.get('series', [])) > 0:\n    for d in db_res['series'][0]['values']:\n        # Your code here...\n        pass`;
            break;

          case 'mysql':
          case 'clickhouse':
          case 'oracle':
          case 'sqlserver':
          case 'postgresql':
            commandArgs = [queryOptions.queryStatement];
            resPicker = `for d in db_res:\n    # Your code here...\n    pass`;
            break;

          case 'redis':
          case 'memcached':
            commandArgs = splitargs(queryOptions.queryStatement);

            resStr = apiRes.data + '';
            if (this.validator.isInt(resStr)) {
              resPicker = `db_res = int(db_res)\n`;
            } else if (this.validator.isFloat(resStr)) {
              resPicker = `db_res = float(db_res)\n`;
            }
            resPicker += `\n# Your code...`;
            break;

          case 'elasticsearch':
            commandArgs = [queryOptions.queryStatement];
            resPicker += `\n# Your code...`;
            break;

          case 'prometheus':
            commandArgs = [queryOptions.queryStatement];
            resPicker += `\n# Your code...`;
            break;
        }

        let getHelperCode = `helper = DFF.CONN('${this.connector.id}')`;
        let doQueryCode   = `db_res = helper.${command}('${(commandArgs || []).join("', '")}')`;

        this.$set(this.latestQueryOptionsMap, this.connector.id, {
          database      : queryOptions.database,
          queryStatement: queryOptions.queryStatement,
          pythonCode    : `${getHelperCode}\n${doQueryCode}\n${resPicker}`,
        });

      } else {
        result.data = this.$t('Query Failed');

        // Add error info
        if (apiRes.message) {
          result.data += '\n\n' + apiRes.message;
        }
        if (apiRes.detail && apiRes.detail.error) {
          result.data += '\n\n' + apiRes.detail.error;
        }
        if (apiRes.detail && apiRes.detail.message) {
          result.data += '\n\n' + apiRes.detail.message;
        }
      }

      this.$set(this.latestQueryResultMap, this.connector.id, result);

      this.isQuerying = false;
    },
    copyCascaderExampleCodeToDebugger() {
      this.latestQueryOptionsMap[this.connector.id].queryStatement = this.browserCascaderExampleCode;
      this.selectedTab = 'debugger';

      this.runDebugger(this.latestQueryOptionsMap[this.connector.id]);
    },
  },
  computed: {
    META_MAP() {
      let startMoment = this.M().add(-1, 'h');
      let endMoment   = this.M();

      // Use alphabets for the first level for Redis
      let REDIS_BROWSER_KEY = {
        title  : this.$t('Keys (a part of)'),
        type   : 'query',
        query  : 'SCAN 0 MATCH "{pattern}" COUNT 100',
        example: 'TYPE "{key}"',
        ref    : 'key',
      }
      let REDIS_BROWSER = {
        title: this.$t('Initial'),
        type : 'static',
        data : [],
      };
      let allChars = [];
      for (let charCode = 'a'.charCodeAt(); charCode <= 'z'.charCodeAt(); charCode++) {
        let char = String.fromCharCode(charCode);
        REDIS_BROWSER.data.push({
          label  : `${char}${char.toUpperCase()}`,
          value  : `[${char.toUpperCase()}${char}]*`,
          example: 'SCAN 0 MATCH "{pattern}" COUNT 100',
          ref    : 'pattern',
          sub    : REDIS_BROWSER_KEY,
        });
        allChars.push(`${char.toUpperCase()}${char}`);
      }
      REDIS_BROWSER.data.push({
        label  : this.$t('Other'),
        value  : `[^${allChars.join()}]*`,
        example: 'SCAN 0 MATCH "{pattern}" COUNT 100',
        ref    : 'pattern',
        sub    : REDIS_BROWSER_KEY,
      });

      return {
        influxdb: {
          supportBrowser : true, // If supports browser (need browser configs)
          supportDebugger: true, // If supports debugger
          supportDatabase: true, // If supports select database
          command        : 'query',
          debuggerName   : this.$t('Run InfluxQL'),
          debuggerExample: ['SELECT * FROM some_measurement LIMIT 10'],
          browser: {
            title         : this.$t('Database'),
            type          : 'query',
            query         : 'SHOW DATABASES',
            example       : 'SHOW MEASUREMENTS ON "{database}"',
            defaultExample: 'SHOW MEASUREMENTS',
            ref           : 'database',
            sub: {
              title: this.$t('Data'),
              type : 'static',
              data: [
                {
                  value         : this.$t('Measurement'),
                  example       : 'SHOW MEASUREMENTS ON "{database}"',
                  defaultExample: 'SHOW MEASUREMENTS',
                  sub: {
                    title         : this.$t('Measurement'),
                    type          : 'query',
                    query         : 'SHOW MEASUREMENTS ON "{database}"',
                    example       : 'SELECT * FROM "{database}".."{measurement}"',
                    defaultExample: 'SELECT * FROM "{measurement}"',
                    ref           : 'measurement',
                    sub: {
                      type: 'static',
                      data: [
                        {
                          value         : this.$t('Tag'),
                          example       : 'SHOW TAG KEYS ON "{database}" FROM "{measurement}"',
                          defaultExample: 'SHOW TAG KEYS FROM "{measurement}"',
                          sub: {
                            title         : this.$t('Tag'),
                            type          : 'query',
                            query         : 'SHOW TAG KEYS ON "{database}" FROM "{measurement}"',
                            example       : 'SELECT * FROM "{database}".."{measurement}" WHERE "{tagKey}" = \'tagValue\'',
                            defaultExample: 'SELECT * FROM "{measurement}" WHERE "{tagKey}" = \'tagValue\'',
                            ref           : 'tagKey',
                          }
                        },
                        {
                          value         : this.$t('Field'),
                          example       : 'SHOW FIELD KEYS ON "{database}" FROM "{measurement}"',
                          defaultExample: 'SHOW FIELD KEYS FROM "{measurement}"',
                          sub: {
                            title         : this.$t('Field'),
                            type          : 'query',
                            query         : 'SHOW FIELD KEYS ON "{database}" FROM "{measurement}"',
                            example       : 'SELECT "{fieldKey}" FROM "{database}".."{measurement}"',
                            defaultExample: 'SELECT "{fieldKey}" FROM "{measurement}"',
                            ref           : 'fieldKey',
                          }
                        },
                      ]
                    }
                  }
                },
                {
                  value         : this.$t('Retention Policie'),
                  example       : 'SHOW RETENTION POLICIES ON "{database}"',
                  defaultExample: 'SHOW RETENTION POLICIES',
                  sub: {
                    title  : this.$t('Retention Policie'),
                    type   : 'query',
                    query  : 'SHOW RETENTION POLICIES ON "{database}"',
                    example: 'SELECT * FROM "{database}"."{retentionPolicy}"."measurement"',
                    ref    : 'retentionPolicy',
                  }
                },
              ],
            },
          },
        },
        mysql: {
          supportBrowser : true,
          supportDebugger: true,
          supportDatabase: true,
          command        : 'query',
          debuggerName   : this.$t('Run SQL'),
          debuggerExample: ['SELECT * FROM `some_table` LIMIT 10'],
          browser: {
            title  : this.$t('Table'),
            type   : 'query',
            query  : 'SHOW TABLES',
            example: 'SELECT * FROM `{table}`',
            ref    : 'table',
            sub: {
              title  : this.$t('Field'),
              type   : 'query',
              query  : 'SHOW FULL COLUMNS FROM `{table}`',
              example: 'SELECT `{field}` FROM `{table}`',
              ref    : 'field',
            },
          },
        },
        redis: {
          supportBrowser : true,
          supportDebugger: true,
          supportDatabase: true,
          command        : 'query',
          debuggerName   : this.$t('Run Command'),
          debuggerExample: ['SCAN', '0', 'COUNT', '10'],
          browser: REDIS_BROWSER,
        },
        memcached: {
          supportLister  : false,
          supportDebugger: true,
          supportDatabase: false,
          command        : 'query',
          debuggerName   : this.$t('Run Command'),
          debuggerExample: ['GET', 'key'],
        },
        clickhouse: {
          supportBrowser : true,
          supportDebugger: true,
          supportDatabase: true,
          command        : 'query',
          debuggerName   : this.$t('Run SQL'),
          debuggerExample: ['SELECT * FROM some_table LIMIT 10'],
          browser: {
            title         : this.$t('Database'),
            type          : 'query',
            query         : 'SHOW DATABASES',
            example       : 'SHOW TABLES FROM `{database}`',
            defaultExample: 'SHOW TABLES',
            ref           : 'database',
            sub: {
              title         : this.$t('Table'),
              type          : 'query',
              query         : 'SHOW TABLES FROM `{database}`',
              example       : 'SELECT * FROM `{database}`.`{table}`',
              defaultExample: 'SELECT * FROM `{table}`',
              ref           : 'table',
              sub: {
                title         : this.$t('Field'),
                type          : 'query',
                query         : 'DESCRIBE TABLE `{database}`.`{table}`',
                example       : 'SELECT `{field}` FROM `{database}`.`{table}`',
                defaultExample: 'SELECT `{field}` FROM `{table}`',
                ref           : 'field',
              },
            },
          },
        },
        oracle: {
          supportBrowser : true,
          supportDebugger: true,
          supportDatabase: true,
          command        : 'query',
          debuggerName   : this.$t('Run SQL'),
          debuggerExample: ['SELECT * FROM SOME_TABLE WHERE ROWNUM <= 10'],
          browser: {
            title  : this.$t('Table'),
            type   : 'query',
            query  : "SELECT TABLE_NAME FROM USER_TABLES",
            example: 'SELECT * FROM "{table}"',
            ref    : 'table',
            sub: {
              title  : this.$t('Field'),
              type   : 'query',
              query  : "SELECT COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME='{table}'",
              example: 'SELECT {field} FROM "{table}"',
              ref    : 'field',
            },
          },
        },
        sqlserver: {
          supportBrowser : true,
          supportDebugger: true,
          supportDatabase: true,
          command        : 'query',
          debuggerName   : this.$t('Run SQL'),
          debuggerExample: ['SELECT TOP 10 * FROM some_table'],
          browser: {
            title  : this.$t('Tables'),
            type   : 'query',
            query  : `SELECT [NAME] FROM [sys].[TABLES]`,
            example: 'SELECT * FROM [{table}]',
            ref    : 'table',
            sub: {
              title  : this.$t('Field'),
              type   : 'query',
              query  : `SELECT NAME FROM SYSCOLUMNS WHERE ID = object_id('{table}')`,
              example: 'SELECT [{field}] FROM [{table}]',
              ref    : 'field',
            },
          },
        },
        postgresql: {
          supportBrowser : true,
          supportDebugger: true,
          supportDatabase: true,
          command        : 'query',
          debuggerName   : this.$t('Run SQL'),
          debuggerExample: ['SELECT * FROM "some_table" LIMIT 10'],
          browser: {
            title         : 'Schema',
            type          : 'query',
            query         : `SELECT DISTINCT "schemaname" FROM "pg_tables" GROUP BY "schemaname" ORDER BY "schemaname"`,
            example       : `SELECT "tablename" FROM "pg_tables" WHERE "schemaname" = 'public'`,
            defaultExample: `SELECT "tablename" FROM "pg_tables" WHERE "schemaname" = 'public'`,
            ref           : 'schema',
            sub: {
              title         : this.$t('Tables'),
              type          : 'query',
              query         : `SELECT "tablename" FROM "pg_tables" WHERE "schemaname" = '{schema}'`,
              example       : 'SELECT * FROM "{schema}"."{table}"',
              defaultExample: 'SELECT * FROM "{table}"',
              ref           : 'table',
              sub: {
                title         : this.$t('Fields'),
                type          : 'query',
                query         : `SELECT "A"."attname" FROM "pg_class" AS "C", "pg_attribute" AS "A" WHERE "A"."attrelid" = "C"."oid" AND "A"."attnum" > 0 AND "C"."relname" = '{table}'`,
                example       : 'SELECT "{field}" FROM "{schema}"."{table}"',
                defaultExample: 'SELECT "{field}" FROM "{table}"',
                ref           : 'field',
              },
            },
          },
        },
        mongodb: {
          supportBrowser : true,
          supportDebugger: true,
          supportDatabase: false,
          command        : 'query',
          debuggerName   : this.$t('Send HTTP Request'),
          debuggerExample: ['GET /_search?q=field:value'],
          browser: {
            title         : this.$t('Database'),
            type          : 'query',
            query         : `{"method": "list_database_names"}`,
            example       : `# Python\ndata = helper.db('{database}')`,
            defaultExample: `# Python\ndata = helper.db()`,
            ref           : 'database',
            sub: {
              title         : this.$t('Collection'),
              type          : 'query',
              query         : `{"method": "list_collection_names", "db_name": "{database}"}`,
              example       : `# Python\ndata = helper.db('{database}')['{collection}'].find_one()`,
              defaultExample: `# Python\ndata = helper.db()['{collection}'].find_one()`,
              ref           : 'collection',
            }
          },
        },
        elasticsearch: {
          supportBrowser : true,
          supportDebugger: true,
          supportDatabase: false,
          command        : 'query',
          debuggerName   : this.$t('Send HTTP Request'),
          debuggerExample: ['GET /_search?q=field:value'],
          browser: {
            title         : this.$t('Index'),
            type          : 'query',
            query         : `GET /_cat/indices`,
            example       : `GET /{index}/_search`,
            defaultExample: `GET /{index}/_search`,
            ref           : 'index',
            sub: {
              title         : this.$t('Fields'),
              type          : 'query',
              query         : `GET /{index}/_mapping`,
              example       : `GET /{index}/_search?q={field}:something`,
              defaultExample: `GET /{index}/_search?q={field}:something`,
              ref           : 'field',
            },
          },
        },
        prometheus: {
          supportBrowser : true,
          supportDebugger: true,
          supportDatabase: false,
          command        : 'query',
          debuggerName   : this.$t('Send HTTP Request'),
          debuggerExample: [`GET /api/v1/query_range?query=up&start=${startMoment.toISOString()}&end=${endMoment.toISOString()}&step=60s`],
          browser: {
            title         : 'Metric',
            type          : 'query',
            query         : `GET /api/v1/label/__name__/values`,
            example       : `GET /api/v1/query_range?query={metric}&start=${startMoment.toISOString()}&end=${endMoment.toISOString()}&step=60s`,
            defaultExample: `GET /api/v1/label/__name__/values`,
            ref           : 'metric',
          }
        },
        aliyunSLS: {
          supportBrowser : true,
          supportDebugger: false,
          supportDatabase: false,
          command        : 'query',
          browser: {
            title         : 'Project',
            type          : 'query',
            command       : 'list_projects',
            example       : null,
            defaultExample: null,
            ref           : 'project',
            sub: {
              title      : 'Logstore',
              type       : 'query',
              command    : 'list_logstores',
              commandArgs: [ '$project' ],
              example    : null,
              ref        : 'logstore',
            },
          }
        },
      }
    },
  },
  props: {
  },
  data() {
    let dragPosition = this.$store.state.asideConnector_connectorSimpleGUIWindowPosition || { left: 10, bottom: 10 };

    return {
      show: false,
      isQuerying: false,
      selectedTab: 'browser',

      showPosition: this.T.jsonCopy(dragPosition),
      dragPosition: this.T.jsonCopy(dragPosition),

      connector: {},

      latestQueryOptionsMap: {},
      latestQueryResultMap : {},

      browserCascaderProps: {
        lazy    : true,
        lazyLoad: this.loadBrowser,
      },
      browserCascaderExampleCode : '',
      browserCascaderErrorMessage: '',
    }
  },
  mounted() {
    window.addEventListener('resize', this.fixShowPosition, false);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.fixShowPosition, false);
  },
}
</script>

<style scoped>
.connector-simple-gui-window {
  position: fixed;
  z-index: 2002;
  height: 360px;
  width: 610px;
  border: 1px;
  border-radius: 5px;
  background-color: var(--base);
  border: 5px solid var(--border);
  box-shadow: var(--shadow);
}
.connector-simple-gui-header {
  cursor: move;
  width: 100%;
  height: 35px;
  border-bottom: 1px solid var(--border);
}
.connector-simple-gui-title {
  font-size: 16px;
  line-height: 35px;
  margin-left: 10px;
}
.connector-simple-gui-close {
  cursor: pointer !important;
  float: right;
  margin-right: 10px;
  line-height: 36px;
}
.connector-simple-gui-debugger {
  padding: 5px;
  padding-bottom: 0;
}
.connector-simple-gui-debugger .el-form-item {
  margin-bottom: 5px !important;
}
.connector-simple-gui-debugger .connector-simple-gui-database {
  width: 180px;
}
.connector-simple-gui-debugger .connector-simple-gui-copy-content {
  float: right;
}
.connector-simple-gui-debugger pre.connector-simple-gui-result {
  padding: 5px;
  border: 1px solid var(--border);
  border-radius: 5px;
  margin: 0;
  font-size: 12px;
  line-height: 16px;
  height: 145px;
  overflow: auto;
  white-space: pre;
}
.connector-simple-gui-debugger pre.connector-simple-gui-query-failed {
  color: var(--danger);
}
.connector-simple-gui-browser {
  padding: 5px;
  padding-bottom: 0;
}
.connector-simple-gui-browser .el-form-item {
  margin-bottom: 5px !important;
}
.connector-simple-gui-browser-cascader-item {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.connector-simple-gui-browser-cascader-item span {
  font-family: monospace;
}
.connector-simple-gui-browser pre.connector-simple-gui-browser-example-code {
  padding: 5px;
  padding-right: 25px;
  border: 1px solid var(--border);
  border-radius: 5px;
  margin: 0;
  height: 40px;
  overflow: auto;
  white-space: pre-wrap;
  font-size: 12px;
  line-height: 14px;
}
.connector-simple-gui-browser .connector-simple-gui-browser-example-code-run {
  position: absolute;
  right: 8px;
  top: 8px;
  font-size: 12px;
}
.connector-simple-gui-browser .connector-simple-gui-browser-error {
  margin: 10px;
}
.builtin {
  color: orangered;
}
</style>

<style>
.connector-simple-gui-window > .el-tabs {
  border: none;
}
.connector-simple-gui-window > .el-tabs > .el-tabs__content {
  width: 100%;
  height: 295px;
  padding: 0;
}
.connector-simple-gui-window > .el-tabs > .el-tabs__header {
  margin-top: 0;
}
.connector-simple-gui-window > .el-tabs > .el-tabs__header .el-tabs__item {
  height: 30px;
  line-height: 30px;
}
.connector-simple-gui-browser-cascader .el-cascader-node {
  height: 22px;
  line-height: 22px;
  font-size: 12px;
  padding-left: 0;
  padding-right: 15px;
}
.connector-simple-gui-browser-cascader .el-cascader-menu {
  min-width: 120px;
}
.connector-simple-gui-browser-cascader.normal-window .el-cascader-menu__wrap {
  height: 224px;
}
.connector-simple-gui-browser-cascader.full-window .el-cascader-menu__wrap {
  height: 284px;
}
.connector-simple-gui-browser-cascader .el-cascader-node__prefix {
  display: none;
}
</style>
